package dxn.nl.export.deal.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson2.JSON;
import dxn.boot.common.entity.CsColumnDto;
import dxn.nl.export.deal.netty.SocketManager;
import dxn.nl.export.deal.service.ImportFileService;
import dxn.nl.export.deal.upload.NoModelDataListener;
import dxn.nl.file.biz.ImportStatusEnum;
import dxn.nl.file.biz.manager.MinIoImageManager;
import dxn.nl.file.biz.po.FileImportFileDetail;
import dxn.nl.file.biz.service.AppModelBaseService;
import dxn.nl.file.biz.service.ImportFileBaseService;
import dxn.nl.file.client.model.dto.CsExportExcelHeadDto;
import dxn.nl.file.client.model.dto.TransferMessageConfig;
import dxn.nl.file.client.model.dto.TransferMessageData;
import dxn.nl.file.client.model.dto.TransferMessageDto;
import dxn.nl.file.client.model.enums.ExportDealResultTypeEnum;
import dxn.nl.file.client.model.enums.ExportFileTypeEnum;
import dxn.nl.file.client.model.enums.ExportMessageTypeEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@Slf4j
@Service
public class ImportFileServiceImpl implements ImportFileService {

    @Resource
    private MinIoImageManager minIoImageManager;

    @Resource
    private ImportFileBaseService importFileBaseService;

    @Resource
    private AppModelBaseService appModelBaseService;

    @Override
    public String dealImportFile(long id) {

        int totalCount  =0 ;
        StringBuilder errorBuffer = new StringBuilder();

        try
        {
            // 查找文件
            FileImportFileDetail fileDetail = importFileBaseService.getBaseMapper().selectById(id);

            if(fileDetail == null)
            {
                return null;
            }

            if (fileDetail.getStatusCode() == null) {
                fileDetail.setStatusCode(0);
            }
            else if (10 == fileDetail.getStatusCode()) {
                // 已经导入完成了就不要再执行了
                return null;
            }

            // 更新开始处理
            importFileBaseService.updateStatus(fileDetail.getId(), ImportStatusEnum.start_deal,totalCount,null);

            // 更新开始处理
            int buckIndex = fileDetail.getFilePath().indexOf("/");
            String bucketName = fileDetail.getFilePath().substring(0,buckIndex);
            String filePath = fileDetail.getFilePath().substring(buckIndex+1);
            if(!minIoImageManager.existBucketName(bucketName))
            {
                String error = "存储桶"+bucketName+"不存在";
                importFileBaseService.updateStatus(fileDetail.getId(), ImportStatusEnum.fail,totalCount,error);
                return error;
            }

            // 获取文件流
            InputStream inputStream = minIoImageManager.getImage("cms-import",filePath);

            if(inputStream == null)
            {
                String error = "文件不存在";
                importFileBaseService.updateStatus(fileDetail.getId(), ImportStatusEnum.fail,totalCount,error);
                return error;
            }

            // 获取Excel表头
            List<CsExportExcelHeadDto> columnDtoList = checkSettingHead(fileDetail.getAppId(),fileDetail.getModeCode(),fileDetail.getOrgCode(),fileDetail.getImportUserCode());
            if(CollectionUtils.isEmpty(columnDtoList))
            {
                String error = "未配置Excel表头";
                importFileBaseService.updateStatus(fileDetail.getId(), ImportStatusEnum.fail,totalCount,error);
                return error;
            }

            // 读取文件字节流
            byte[] fileBytes;
            try(ByteArrayOutputStream firstOutput = new ByteArrayOutputStream())
            {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    firstOutput.write(buffer, 0, bytesRead);
                }
                fileBytes = firstOutput.toByteArray();
            }

            // 重新转化输入流
            try(ByteArrayInputStream fileInputStream = new ByteArrayInputStream(fileBytes))
            {
                // 如若是zip压缩包，先解压，在循环读取
                if(fileDetail.getFileName().endsWith(".zip"))
                {
                    try(ZipInputStream zis = new ZipInputStream(fileInputStream)) {
                        ZipEntry ze = zis.getNextEntry();

                        while (ze != null) {
                            String fileName = ze.getName();
                            log.info("解压后的文件：{}",fileName);

                            // 读取文件流
                            byte[] bytes;
                            try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream())
                            {
                                int len;
                                byte[] buffer = new byte[1024];
                                while ((len = zis.read(buffer)) > 0) {
                                    outputStream.write(buffer, 0, len);
                                }
                                bytes = outputStream.toByteArray();
                            }

                            // 关闭当前ZipEntry并移至下一个
                            zis.closeEntry();

                            // 转化为内存输入流，解析Excel
                            try(ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes))
                            {
                                Pair<Integer,String> pair = dealData(byteArrayInputStream,fileName,fileDetail,columnDtoList);
                                totalCount += pair.getKey();
                                if(StringUtils.isNotBlank(pair.getValue()))
                                {
                                    errorBuffer.append(pair.getValue());
                                    break;
                                }
                            }

                            ze = zis.getNextEntry();
                        }
                    }
                }
                else
                {
                    // Excel文件直接处理
                    Pair<Integer,String> pair = dealData(fileInputStream,fileDetail.getFileName(),fileDetail,columnDtoList);
                    totalCount += pair.getKey();
                    if(StringUtils.isNotBlank(pair.getValue()))
                    {
                        errorBuffer.append(pair.getValue());
                    }
                }
            }

            // 记录结果，更新
            fileDetail.setLastDealRow(totalCount);
            if(errorBuffer.isEmpty())
            {
                importFileBaseService.updateStatus(fileDetail.getId(), ImportStatusEnum.ok,totalCount,null);
                return null;
            }

            String error2 = errorBuffer.toString();
            importFileBaseService.updateStatus(fileDetail.getId(), ImportStatusEnum.fail,totalCount,error2);
            log.debug("文件处理结束 {}",fileDetail.getFilePath());
            return error2;
        }
        catch (Exception ex)
        {
            log.error("",ex);
            importFileBaseService.updateStatus(id, ImportStatusEnum.fail,totalCount,ex.getMessage());
            return ex.toString();
        }
    }

    public List<CsExportExcelHeadDto> checkSettingHead(String appId,String modeCode,String orgCode,String userCode)
    {
        List<CsColumnDto> columnDtos = appModelBaseService.selectImportTemplateByUser(orgCode,
                userCode, modeCode);

        if(!CollectionUtils.isEmpty(columnDtos))
        {
            List<CsExportExcelHeadDto> resultList= new ArrayList<>();
            for(CsColumnDto dto:columnDtos)
            {
                CsExportExcelHeadDto headDto = new CsExportExcelHeadDto();
                headDto.setOrder(dto.getOrder());
                headDto.setKey(dto.getDataIndex());
                headDto.setTitle(Arrays.stream(dto.getTitle().split(",")).toList());
                //headDto.setDataType(dto.get());
                headDto.setColumnLength(dto.getWidth());
                resultList.add(headDto);
            }
            return resultList;
        }

        TransferMessageDto csNioMessage = new TransferMessageDto();
        csNioMessage.setConfig(new TransferMessageConfig());
        csNioMessage.setMessageData(new TransferMessageData());
        csNioMessage.setType(ExportMessageTypeEnum.query_head.code);

        csNioMessage.getConfig().setId(UUID.randomUUID().toString());
        csNioMessage.getConfig().setAppId(appId);
        csNioMessage.getConfig().setModeCode(modeCode);
        csNioMessage.getConfig().setServer(SocketManager.appSessionId);
        csNioMessage.getConfig().setFileType(ExportFileTypeEnum.upload.code);

        csNioMessage = SocketManager.sendData(csNioMessage,false);

        if(csNioMessage.getConfig().getDealResult() == ExportDealResultTypeEnum.fail.code)
        {
            throw new RuntimeException(csNioMessage.getConfig().getErrorMessage());
        }

        if(csNioMessage.getData() != null && csNioMessage.getData().length>0)
        {
            List<CsExportExcelHeadDto> queryHeadList = JSON.parseArray(csNioMessage.getData(),CsExportExcelHeadDto.class);
            if(!CollectionUtils.isEmpty(queryHeadList))
            {
                return queryHeadList;
            }
        }

        return null;
    }

    private Pair<Integer,String> dealData(InputStream inputStream, String fileName, FileImportFileDetail fileDetail, List<CsExportExcelHeadDto> dtos)
    {
        NoModelDataListener noModelDataListener = new NoModelDataListener(fileDetail,importFileBaseService,dtos);

        try {
            if (fileName.endsWith(".xls")) {
                EasyExcel.read(inputStream, noModelDataListener).excelType(ExcelTypeEnum.XLS).sheet().doRead();
            }
            else if (fileName.endsWith(".csv")) {
                EasyExcel.read(inputStream, noModelDataListener).excelType(ExcelTypeEnum.CSV).sheet().doRead();
            }
            else if (fileName.endsWith(".xlsx")) {
                EasyExcel.read(inputStream, noModelDataListener).excelType(ExcelTypeEnum.XLSX).sheet().doRead();
            }
            else
            {
                EasyExcel.read(inputStream, noModelDataListener).sheet().doRead();
            }
        }
        catch (Exception ex)
        {
            log.error("",ex);
            return Pair.of(0,ex.getMessage());
        }

        return Pair.of(noModelDataListener.lastDealRow,noModelDataListener.failMessage);
    }
}
